package com.redis.springtest;

import com.redis.springtest.config.RedisConfig;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.data.redis.connection.RedisZSetCommands;
import org.springframework.data.redis.core.DefaultTypedTuple;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ZSetOperations;

import java.util.HashSet;
import java.util.Iterator;
import java.util.Objects;
import java.util.Set;

/**
 * Created with IntelliJ IDEA.
 * Description:
 *
 * @author lzy
 * @create 2020-07-27 下午2:46
 */
public class AppRedisZset {
    public static void main(String[] args) {
        AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(RedisConfig.class);
        final RedisTemplate redisTemplate = ctx.getBean(RedisTemplate.class);
        final ZSetOperations zSetOperations = redisTemplate.opsForZSet();

        // Spring提供了TypedTuple操作有序集合
        Set<ZSetOperations.TypedTuple> set1 = new HashSet<>();
        Set<ZSetOperations.TypedTuple> set2 = new HashSet<>();

        int j = 9;
        for (int i = 1; i <= 9; i++) {
            j--;
            // 计算分数和值
            final Double score1 = Double.valueOf(i);
            String value1 = "x" + i;
            final Double score2 = Double.valueOf(j);
            String value2 = j % 2 == 1 ? "y" + j : "x" + j;
            // 使用Spring提供的默认TypedTuple:DefaultTypedTuple
            final ZSetOperations.TypedTuple typedTuple1 = new DefaultTypedTuple<>(value1, score1);
            set1.add(typedTuple1);
            final ZSetOperations.TypedTuple typedTuple2 = new DefaultTypedTuple<>(value2, score2);
            set2.add(typedTuple2);
        }

        // 将元素插入有序集合中zset1
        redisTemplate.opsForZSet().add("zset1", set1);
        redisTemplate.opsForZSet().add("zset2", set2);

        // 统计总数
        Long size = null;
        size = redisTemplate.opsForZSet().zCard("zset1");
        // 分数记为score, 那么下面方法就是要求3<=score<=6的元素
        size = zSetOperations.count("zset1", 3, 6);

        // 从下标1开始截取5个元素,但是不返回分数, 每一个元素是string
        final Set zset1 = zSetOperations.range("zset1", 1, 5);
        printSet(zset1);

        // 截取集合所有元素, 并且对集合按分数排序，并返回分数
        final Set zset11 = zSetOperations.rangeWithScores("zset1", 0, -1);
        printTypedTuple(zset11);

        // 将zset1和zset2两个集合的交集放到集合inter_set中
        final Long aLong = zSetOperations.intersectAndStore("zset1", "zset2", "inter_zset");
        // 区间
        RedisZSetCommands.Range range = RedisZSetCommands.Range.range();
        range.lt("x8");
        range.gt("x1");
        final Set zset12 = zSetOperations.rangeByLex("zset1", range);
        printSet(zset12);

        range.lte("x8");
        range.gte("x1");
        final Set zset13 = zSetOperations.rangeByLex("zset1", range);
        printSet(zset13);

        // 限制返回个数
        RedisZSetCommands.Limit limit = RedisZSetCommands.Limit.limit();
        limit.count(4);
        // 限制从第5个开始截取
        limit.offset(5);
        // 求区间内的元素，并限制返回4条
        final Set zset14 = zSetOperations.rangeByLex("zset1", range, limit);
        printSet(zset14);

        // 求排行, 排名第1返回0, 第2返回1
        final Long rank = zSetOperations.rank("zset1", "x4");
        System.out.println("rank = " + rank);

        // 删除元素返回删除个数
        Long remove = zSetOperations.remove("zset1", "x5", "x6");
        System.out.println("remove size =" + remove);

        // 按照排行删除从0开始算起, 这里将删除排行为2和3的元素
        Long zset2 = zSetOperations.removeRange("zset2", 1, 2);
        // 获取所有集合的元素和分数，以-1代表全部元素
        Set set = zSetOperations.rangeWithScores("zset2", 0, -1);
        printTypedTuple(set);

        // 删除指定的元素
        Long remove1 = zSetOperations.remove("zset2", "y5", "y3");
        System.out.println(remove1);

        // 给集合中一个元素的分数加上11
        Double aDouble = zSetOperations.incrementScore("zset1", "x1", 11);
        zSetOperations.removeRangeByScore("zset1", 1, 2);
        Set zset21 = zSetOperations.reverseRangeByScoreWithScores("zset2", 1, 10);
        printTypedTuple(zset21);

    }

    private static void printTypedTuple(Set<ZSetOperations.TypedTuple> set) {
        if (Objects.isNull(set) || set.isEmpty()) {
            return;
        }

        final Iterator<ZSetOperations.TypedTuple> iterator = set.iterator();
        while (iterator.hasNext()) {
            final ZSetOperations.TypedTuple next = iterator.next();
            System.out.println("{value=" + next.getValue() + ", score=" + next.getScore() + "}\n");
        }

    }

    private static void printSet(Set set) {
        if (Objects.isNull(set) || set.isEmpty()) {
            return;
        }

        final Iterator iterator = set.iterator();
        while (iterator.hasNext()) {
            final Object next = iterator.next();
            System.out.println(next + "\n");
        }

    }
}
